/**
 * @file ObservationManager.cpp
 *
 * Obsługa bazy danych obserwacji - implementacja.
 *
 * @author Zbigniew Siciarz
 * @date 2009
 * @version 2.0.0
 * @since 2.0.0
 */
#include "ObservationManager.h"

#include "Exceptions.h"
#include <QMessageBox>
#include <QtSql>

namespace Dogz
{
    /**
     * Tworzy tabele obserwacji.
     */
    void ObservationManager::createTables()
    {
        QSqlDatabase db = QSqlDatabase::database();
        // zaczynamy transakcję
        db.transaction();

        // tworzenie struktury tabeli
        QSqlQuery query("CREATE TABLE IF NOT EXISTS base_observations ("
                        "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                        "star_name VARCHAR(30) NOT NULL,"
                        "jd DOUBLE NOT NULL,"
                        "magnitude DOUBLE NOT NULL,"
                        "fainter_than INT DEFAULT 0 NOT NULL,"
                        "comp_star_name VARCHAR(30),"
                        "chart_date VARCHAR(10),"
                        "comment_codes VARCHAR(15),"
                        "notes TEXT"
                        ")");

        if (!query.isActive())
        {
            db.rollback();
            throw Dogz::DbException(query);
        }

        // wszystko poszło ok, więc kończymy transakcję sukcesem
        db.commit();
    }

    /**
     * Usuwa wszystkie obserwacje z tabeli - korzystać z rozwagą!
     */
    void ObservationManager::clearTables()
    {
        QSqlQuery query("DELETE FROM base_observations");
        if (!query.isActive())
        {
            throw Dogz::DbException(query);
        }
    }

    /**
     * Dodaje nową obserwację wizualną do bazy danych.
     *
     * @param observation obserwacja pochodząca np. z formularza
     * @return identyfikator dodanej obserwacji, lub -1 gdy się nie udało
     */
    int ObservationManager::addObservation(const VisualObservation& observation)
    {
        QSqlDatabase db = QSqlDatabase::database();
        db.transaction();

        QSqlQuery query;
        query.prepare("INSERT INTO base_observations (star_name, jd, magnitude,"
                      "fainter_than, comp_star_name, chart_date, comment_codes,"
                      "notes) VALUES(:star_name, :jd, :magnitude, :fainter_than,"
                      ":comp_star_name, :chart_date, :comment_codes, :notes)");
        query.bindValue(":star_name", observation.getStarName());
        query.bindValue(":jd", observation.getJd());
        query.bindValue(":magnitude", observation.getMagnitude());
        query.bindValue(":fainter_than", observation.isFainterThan());
        query.bindValue(":comp_star_name", observation.getCompStarName());
        query.bindValue(":chart_date", observation.getChartDate());
        query.bindValue(":comment_codes", observation.getCommentCodes());
        query.bindValue(":notes", observation.getNotes());

        query.exec();
        if (!query.isActive())
        {
            db.rollback();
            throw Dogz::DbException(query);
        }

        db.commit();
        QVariant lastId = query.lastInsertId();
        return lastId.isValid() ? lastId.toInt() : -1;
    }

    /**
     * Zwraca listę obserwacji wykonanych pomiędzy dwiema datami w JD.
     *
     * @param jdFrom początkowe JD
     * @param jdTo końcowe JD
     * @return lista obserwacji
     */
    QList<VisualObservation> ObservationManager::getObservations(double jdFrom,
            double jdTo)
    {
        QList<VisualObservation> observations;

        QSqlQuery query;
        query.prepare("SELECT * FROM base_observations "
                "WHERE jd BETWEEN :jd_from AND :jd_to ORDER BY jd ASC");
        query.bindValue(":jd_from", jdFrom);
        query.bindValue(":jd_to", jdTo);
        query.exec();
        if (!query.isActive())
        {
            throw Dogz::DbException(query);
        }

        while (query.next())
        {
            VisualObservation obs;
            obs.setStarName(query.value(StarName).toString());
            obs.setJd(query.value(Jd).toDouble());
            obs.setMagnitude(query.value(Magnitude).toDouble());
            observations.append(obs);
        }

        return observations;
    }

    /**
     * Zwraca obserwację odpowiadającą danemu wierszowi w tabeli.
     *
     * @param index obiekt typu QModelIndex wskazujący na któreś pole wiersza
     * @return obiekt obserwacji
     */
    VisualObservation ObservationManager::getByModelIndex(const QModelIndex& index)
    {
        int row = index.row();
        const QSqlTableModel* model =
            static_cast<const QSqlTableModel*>(index.model());

        QString starName = model->index(row, ObservationManager::StarName).
                data().toString();

        double jd = model->index(row, ObservationManager::Jd).data().toDouble();

        float mag;
        if (model->index(row, ObservationManager::Magnitude).
                data().toString().indexOf('<')==0)
        {
            mag = model->index(row, ObservationManager::Magnitude).
                data().toString().mid(1).toDouble();
        }
        else
        {
            mag = model->index(row, ObservationManager::Magnitude).
                data().toDouble();
        }

        bool fainter = model->index(row, ObservationManager::Magnitude).
                data().toString().indexOf('<')==0;

        VisualObservation obs;
        obs.setStarName(starName);
        obs.setJd(jd);
        obs.setMagnitude(mag);
        obs.setFainterThan(fainter);

        return obs;
    }
}
